/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jmodcog2.map.pix;

import com.amd.aparapi.Range;

/**
 *
 * @author Mitch
 */
public class TrainedFeatureMap extends FeatureMap {

    private final Range ExRange;
    @Constant
    float[] node_vecs;

    public TrainedFeatureMap(FeatureMapConfig config) {
        super(config, true);
        this.node_vecs = new float[num_nodes * vec_size];
        this.local_err = new float[vec_size];
        put(local_err);
        put(node_vecs);
        ExRange = Range.create3D(num_units_x, num_units_y, num_nodes * vec_size, 1, 1, vec_size);
    }
    static final float MAX_ERR = Float.MAX_VALUE;

    void _find_winner(int unit_x, int unit_y) {
        int n = 0;
        int win = -1;
        float e = MAX_ERR;
        int index0 = _err_index(unit_x, unit_y, 0);
        float temp = 0;
        while (n < num_nodes) {
            temp = node_sum_err[index0 + n];
            if (temp < e) {
                win = n;
                e = temp;
            }
            n += 1;
        }
        index0 = _output_index(unit_x, unit_y, 0);
        int pos0 = win * num_node_dims;
        n = 0;
        while (n < num_node_dims) {
            output[index0 + n] = node_pos[pos0 + n];
            n += 1;
        }

    }
    @Local
    float[] local_err;

    void _calc_err() {
        int unit_x = getGlobalId(0);
        int unit_y = getGlobalId(1);
        int node = getGlobalId(2) / vec_size;
        int lid = getLocalId(2);
        if (lid < vec_size) {
            local_err[lid] = _calc_local_err(unit_x, unit_y, node, lid);
        }
        localBarrier();

        if (normalize) {
            float min = MAX_POS;
            float max = MAX_NEG;

            int i = 0;
            float v = 0;
            while (i < vec_size) {
                v = local_err[i];
                if (v < min) {
                    min = v;
                }
                if (v > max) {
                    max = v;
                }
                i += 1;
            }
            if (lid < vec_size) {
                if (min != max) {
                    local_err[lid] = (local_err[lid] - min) / (max - min);
                } else {
                    local_err[lid] = 1;
                }
            }
            localBarrier();
        }

        if (lid == 0) {
            float sum = 0;
            int i = 0;
            while (i < vec_size) {
                sum += _sq(local_err[i]);
                i += 1;
            }
            node_sum_err[_err_index(unit_x, unit_y, node)] = sum;
        }
    }

    float _calc_local_err(int unit_x, int unit_y, int node, int vec_index) {
        int vx = _get3D_i(vec_index, unit_len_y, len_z);
        int vy = _get3D_j(vec_index, unit_len_y, len_z);
        int vz = _get3D_k(vec_index, len_z);
        //
        int input_vi = _get3D_n(unit_x * step_x + vx,
                unit_y * step_y + vy, vz, input_len_y, len_z);

        int node_vi = _get2D_n(node, vec_index, vec_size);

        float in_val = input[input_vi];
        float node_val = node_vecs[node_vi];
        return in_val - node_val;
    }

    @Override
    protected void _run(int mode) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public float[] getOutput() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean process(float[] input) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    protected float _get_node_w(int node_vec_index) {
        return node_vecs[node_vec_index];
    }
}
